home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume11 / syslog.sysv < prev    next >
Encoding:
Internet Message Format  |  1987-09-15  |  10.8 KB

  1. Subject:  v11i050:  SystemV version of syslog
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rs@uunet.UU.NET
  5.  
  6. Submitted-by: Johan Vromans <mcvax!mh.nl!jv>
  7. Posting-number: Volume 11, Issue 50
  8. Archive-name: syslog.sysv
  9.  
  10. [  I understand my "younger brother" Brandon is working on a complete
  11.    4.3BSD-compatible version that uses named pipes.  Keep up the great
  12.    work, folks:  maybe we can get this as part of the Posvidix or
  13.    something.  --r$  ]
  14.  
  15. This is a more realistic syslog development version. It is designed for
  16. System V with IPC (it uses message queues). I linked it to my sendmail for
  17. debugging purposes.
  18. It is not full-blown (it does not take a configuration file) but has proven
  19. to be very usefull.
  20.  
  21. One special remark: because the logfile is default written on the /tmp
  22. filesystem, and our /tmp filesystems are cleaned up daily, an alarm timer is
  23. used to write a timestamp record 24 hours after the last activity to
  24. prevent the logfile from being removed due to lack of access.
  25.  
  26. --
  27. Johan Vromans                              | jv@mh.nl via European backbone
  28. Multihouse N.V., Gouda, the Netherlands    | uucp: ..{?????!}mcvax!mh.nl!jv
  29. "It is better to light a candle than to curse the darkness"
  30.  
  31. -------------------------------- cut here --------------------------------
  32. #! /bin/sh
  33. # This is a shell archive, meaning:
  34. # 1. Remove everything above the #! /bin/sh line.
  35. # 2. Save the resulting text in a file.
  36. # 3. Execute the file with /bin/sh (not csh) to create:
  37. #    makefile
  38. #    syslog.c
  39. #    sendlog.c
  40. # This archive created: Thu Sep  3 09:35:37 1987
  41. export PATH; PATH=/bin:/usr/bin:$PATH
  42. echo shar: "extracting 'makefile'" '(419 characters)'
  43. if test -f 'makefile'
  44. then
  45.     echo shar: "will not over-write existing file 'makefile'"
  46. else
  47. cat << \SHAR_EOF > 'makefile'
  48.  
  49. CFLAGS    = -O
  50. syslog:    syslog.c
  51.     $(CC) $(CFLAGS) -o syslog syslog.c
  52.  
  53. libsyslog.a:    syslog.c
  54.     $(CC) $(CFLAGS) -DLIB_SYSLOG -c syslog.c
  55.     ar r libsyslog.a syslog.o
  56.  
  57. sendlog:    sendlog.c libsyslog.a
  58.     $(CC) $(CFLAGS) -o sendlog sendlog.c libsyslog.a
  59.  
  60. install:    syslog libsyslog.a
  61.     cp syslog /etc/syslog
  62.     chmod 0555 /etc/syslog
  63.     cp libsyslog.a /usr/lib/libsyslog.a
  64.     chmod 0444 /usr/lib/libsyslog.a
  65.  
  66. all:    syslog sendlog libsyslog.a
  67. SHAR_EOF
  68. if test 419 -ne "`wc -c < 'makefile'`"
  69. then
  70.     echo shar: "error transmitting 'makefile'" '(should have been 419 characters)'
  71. fi
  72. fi
  73. echo shar: "extracting 'syslog.c'" '(7709 characters)'
  74. if test -f 'syslog.c'
  75. then
  76.     echo shar: "will not over-write existing file 'syslog.c'"
  77. else
  78. cat << \SHAR_EOF > 'syslog.c'
  79. #ifdef LIB_SYSLOG
  80. static char SCCS_ID[] = "@(#)@ syslog    1.8 system logger";
  81. #else
  82. static char SCCS_ID[] = "@(#)@ syslog    1.8 syslog.o";
  83. #endif
  84. static char CPYRGHT[] = "@(#)@ (c) Multihouse Group Support";
  85. /*
  86.  * usage: /etc/syslog [ logfilename ]
  87.  *
  88.  *    default logfilename: /tmp/syslog.log
  89.  *
  90.  * use    "kill -1  pid"    to release and re-open the logfile
  91.  *    "kill -15 pid"    to exit the program and remove the message queue
  92.  *
  93.  * Reasons to terminate:
  94.  *
  95.  *  0:    normal (catched a SIGTERM)
  96.  *  1:    could not reopen logfile after SIGHUP
  97.  *  2:    error during message recveive
  98.  *  3:    catched another signal
  99.  *
  100.  * define LIB_SYSLOG to obtain a library of access routines
  101.  */
  102.  
  103. #include <stdio.h>
  104. #include <sys/types.h>
  105. #include <sys/ipc.h>
  106. #include <sys/msg.h>
  107. #include <unistd.h>
  108. #include <signal.h>
  109. #include <errno.h>
  110.  
  111. #define TRUE    1
  112. #define FALSE    0
  113. #define EOS    '\0'
  114. #define SIG_ERR    ((int (*)())-1)
  115.  
  116. static int msgkey = -1;
  117. static int msgid = -1;
  118. static char *msgnam = "/etc/syslog";    /* used for ftok! */
  119.  
  120. #define SYSLOG_MAGIC    0xfeff
  121. #define MSG_SIZE    512
  122.  
  123. static struct {
  124.     long type;            /* must be SYSLOG_MAGIC */
  125.     long tm;            /* timestamp */
  126.     unsigned char class;    /* message class */
  127.     unsigned char length;    /* length of msg.text */
  128.     short pid;            /* pid of sending process */
  129.     short uid;            /* uid of sending process */
  130.     char text[MSG_SIZE];    /* text of the message */
  131.   } msg;
  132.  
  133. #ifndef LIB_SYSLOG
  134.  
  135. static struct {
  136.     long type;            /* must be not SYSLOG_MAGIC */
  137.     char text[MSG_SIZE];
  138.   } oldmsg;
  139.  
  140. static char *lognam = "/tmp/syslog.log";
  141. static FILE *logfile = NULL;
  142.  
  143. #define MAXERRCNT    10    /* max number of conseq. recv errors */
  144.  
  145. static char *msgclass[] = {
  146.     "ALERT",
  147.     "SALERT",
  148.     "EMERG",
  149.     "ERROR",
  150.     "CRIT",
  151.     "WARNING",
  152.     "NOTICE",
  153.     "INFO",
  154.     "DEBUG"
  155. };
  156.  
  157. /* signal catchers */
  158.  
  159. static int hup = FALSE;
  160. static int term = FALSE;
  161. static int timedout = FALSE;
  162. static int delay = 24 * 60 * 60;
  163.  
  164. int timeout ()
  165. {
  166.     timedout = TRUE;
  167.     (void) signal (SIGALRM, timeout);
  168. }
  169.  
  170. int sighup ()
  171. {
  172.     hup = TRUE;
  173.     (void) signal (SIGHUP, sighup);
  174. }
  175.  
  176. int sigterm ()
  177. {
  178.     term = TRUE;
  179.     (void) signal (SIGTERM, sigterm);
  180. }
  181.  
  182. int sigcatch ()
  183. {
  184.     terminate (3);
  185. }
  186.  
  187. terminate (why)
  188. int why;
  189. {
  190.     (void) msgctl (msgid, IPC_RMID, ((struct msqid_ds *) NULL));
  191.     if (logfile != NULL) {
  192.     if (why == 0 && term)
  193.         sprintf (msg.text, "normal termination (caught SIGTERM)");
  194.     else
  195.         sprintf (msg.text, "terminated reason=%d", why);
  196.     putlog (TRUE);
  197.     }
  198.     fclose (logfile);
  199.     exit (why);
  200. }
  201.  
  202. catchit (sig)
  203. int sig;
  204. {
  205.     int (*sg)();
  206.     sg = signal (sig, sigcatch);
  207.     if (sg != SIG_DFL && sg != SIG_ERR)
  208.     signal (sig, sg);
  209. }
  210.  
  211. main (argc, argv)
  212. int argc;
  213. char *argv[];
  214. {
  215.     char *cp;
  216.     int errcnt = 0;
  217.  
  218.     msgkey = ftok (msgnam, 0);
  219.     if (msgkey < 0) {
  220.     perror ("ftok");
  221.     exit (2);
  222.     }
  223.  
  224.     msgid = msgget (msgkey, IPC_CREAT | IPC_EXCL | 0722);
  225.     while (msgid < 0) {
  226.     if (errno = EEXIST) {
  227.         fprintf (stderr, "syslog: warning - queue already exists\n");
  228.         msgid = msgget (msgkey, IPC_CREAT | 0722);
  229.     }
  230.     else {
  231.         perror ("msgget");
  232.         exit (2);
  233.     }
  234.     }
  235.  
  236.     if (argc > 1)
  237.     lognam = *++argv;
  238.  
  239.     /* open logfile with correct protection */
  240.     umask (022);
  241.     logfile = fopen (lognam, "a");
  242.     if (logfile == NULL) {
  243.     perror ("open logfile");
  244.     exit (2);
  245.     }
  246.  
  247.     /* make sure no other logger is active */
  248.     if (lockf (fileno (logfile), F_TEST, 0l) < 0) {
  249.     perror ("syslog: cannot lock logfile");
  250.     exit (2);
  251.     }
  252.  
  253. #ifndef DEBUG
  254.     /* detach */
  255.     if (fork ())
  256.     exit (0);
  257.  
  258.     setpgrp ();            /* forget where we came from */
  259.  
  260.     /* re-claim the logfile (we lost the lock because we are a fork) */
  261.     if (lockf (fileno (logfile), F_TLOCK, 0l) < 0) {
  262.     perror ("syslog: logfile lock failed");
  263.     exit (2);
  264.     }
  265. #endif
  266.  
  267.     /* catch SIGHUP and SIGTERM */
  268.     (void) signal (SIGTERM, sigterm);
  269.     (void) signal (SIGHUP, sighup);
  270.  
  271.     /* ignore SIGINT and SIGQUIT */
  272.     (void) signal (SIGINT, SIG_IGN);
  273.     (void) signal (SIGQUIT, SIG_IGN);
  274.  
  275.     /* set alarm */
  276.     (void) signal (SIGALRM, timeout);
  277.  
  278.     strcpy (msg.text, "started");
  279.     putlog (TRUE);
  280.  
  281.     for (;;) {
  282.     int res = msgrcv (msgid, &msg, MSG_SIZE, 0, 0 & MSG_NOERROR);
  283.     if (res >= 0) {
  284.         if (msg.type != SYSLOG_MAGIC) {
  285.         memcpy (&oldmsg, &msg, sizeof (oldmsg));
  286.         (void) time (&msg.tm);
  287.         msg.class = oldmsg.type;
  288.         msg.length = strlen (oldmsg.text);
  289.         msg.type = SYSLOG_MAGIC;
  290.         msg.pid = msg.uid = -1;
  291.         strcpy (msg.text, oldmsg.text);
  292.         }
  293.         putlog (FALSE);
  294.         errcnt = 0;
  295.     }
  296.     else {
  297.         /* message receive error */
  298.         if (errno == EINTR) {
  299.         /* receive was interrupted */
  300.         if (hup) {
  301.             /* catched SIGHUP => release logfile */
  302.             strcpy (msg.text, "logfile released (caught SIGHUP)");
  303.             putlog (TRUE);
  304.             fclose (logfile);
  305.             logfile = fopen (lognam, "a");
  306.             if (logfile == NULL) {
  307.             perror ("reopen logfile");
  308.             terminate (1);
  309.             }
  310.             strcpy (msg.text, "logfile reopened after SIGHUP");
  311.             putlog (TRUE);
  312.             hup = FALSE;
  313.         }
  314.         if (term) {
  315.             /* catched SIGTERM => exit receive loop */
  316.             break;
  317.         }
  318.         if (timedout) {
  319.             strcpy (msg.text, "timestamp");
  320.             putlog (TRUE);
  321.             timedout = FALSE;
  322.         }
  323.         /* otherwise, retry */
  324.         errcnt = 0;
  325.         continue;
  326.         }
  327.         else {
  328.         /* other message receive error */
  329.         sprintf (msg.text, "msgrcv error %d", errno);
  330.         putlog (TRUE);
  331.         if (errcnt++ > MAXERRCNT)
  332.             terminate (2);
  333.         }
  334.     }
  335.     }
  336.  
  337.     /* come here to exit the program */
  338.     terminate (0);
  339. }
  340.  
  341. putlog (internal)
  342. int internal;
  343. {
  344.     long time();
  345.     char *ctime();
  346.     long now = (internal) ? time (&now) : msg.tm;
  347.     register char *date = ctime (&now);
  348.  
  349.     if (internal) {
  350.     msg.pid = getpid ();
  351.     msg.uid = getuid ();
  352.     msg.length = strlen (msg.text);
  353.     }
  354.  
  355.     fprintf (logfile, "%.2s-%.3s-%.2s %.8s", date+8, date+4, date+22, date+11);
  356.  
  357.     if (msg.pid >= 0)
  358.     fprintf (logfile, "%6d ", msg.pid);
  359.     else
  360.     fprintf (logfile, "       ");
  361.  
  362.     if (msg.uid >= 0)
  363.     fprintf (logfile, "%6d ", msg.uid);
  364.     else
  365.     fprintf (logfile, "       ");
  366.  
  367.     if (internal)
  368.     fprintf (logfile, "SYSLOG  ");
  369.     else
  370.     if (msg.class > 0 && msg.class < 10)
  371.     fprintf (logfile, "%-7s ", msgclass[msg.class-1]);
  372.     else
  373.     fprintf (logfile, "?%-7d", msg.class);
  374.  
  375.     fprintf (logfile, "%.*s", msg.length, msg.text);
  376.  
  377.     /* append newline if needed */
  378.     if (msg.text[msg.length-1] != '\n')
  379.         fprintf (logfile, "\n");
  380.  
  381.     fflush (logfile);
  382.  
  383.     /* set new time out */
  384.     alarm (delay);
  385. }
  386.  
  387. #endif !LIB_SYSLOG
  388.  
  389. #ifdef LIB_SYSLOG
  390.  
  391. #define MAX_LOGNAME    32
  392. #define MAX_BUF    256
  393. static char logname[MAX_LOGNAME] = "";
  394.  
  395. /* chkque - checks message queue existence */
  396.  
  397. static int
  398. chkque ()
  399. {
  400.     if (msgid == -1)
  401.     msgid = msgget (ftok (msgnam, 0), 0, 0);
  402.     return (msgid != -1);
  403. }
  404.  
  405. /* openlog - sets up logname; checks message queue existence */
  406.  
  407. int
  408. openlog (tag)
  409. char *tag;
  410. {
  411.     strncpy (logname, tag, MAX_LOGNAME);
  412.     logname[MAX_LOGNAME-1] = EOS;
  413.     return (chkque () ? 0 : -1);
  414. }
  415.  
  416. /* syslog - writes message to system logger */
  417.  
  418. int
  419. syslog (class, fmt, p1, p2, p3, p4, p5, p6, p7, p8, p9)
  420. int class;
  421. char *fmt;
  422. {
  423.     if (logname[0])
  424.     sprintf (msg.text, "%s: ", logname);
  425.     sprintf (msg.text+strlen(msg.text),
  426.         fmt, p1, p2, p3, p4, p5, p6, p7, p8, p9);
  427.     if (!chkque ())
  428.     return (-1);
  429.     msg.type = SYSLOG_MAGIC;
  430.     (void) time (&msg.tm);
  431.     msg.class = class;
  432.     msg.pid = getpid ();
  433.     msg.uid = getuid ();
  434.     msg.length = strlen (msg.text);
  435.     return (msgsnd (msgid, &msg, sizeof (msg) - MSG_SIZE + msg.length + 1, 0));
  436. }
  437.  
  438. /* closelog - close message queue, resets logname */
  439.  
  440. void
  441. closelog ()
  442. {
  443.     msgid = -1;
  444.     logname[0] = EOS;
  445. }
  446.  
  447. #ifdef TEST
  448.  
  449. main () {
  450.     openlog ("test");
  451.     syslog (55, "test message %d", 4);
  452. }
  453.  
  454. #endif TEST
  455.  
  456. #endif LIB_SYSLOG
  457. SHAR_EOF
  458. if test 7709 -ne "`wc -c < 'syslog.c'`"
  459. then
  460.     echo shar: "error transmitting 'syslog.c'" '(should have been 7709 characters)'
  461. fi
  462. fi
  463. echo shar: "extracting 'sendlog.c'" '(370 characters)'
  464. if test -f 'sendlog.c'
  465. then
  466.     echo shar: "will not over-write existing file 'sendlog.c'"
  467. else
  468. cat << \SHAR_EOF > 'sendlog.c'
  469. static char SCCS_id[] = "@(#)@ sendlog    1.2 - syslog interface";
  470.  
  471. #include <stdio.h>
  472. #include <sys/syslog.h>
  473.  
  474. main (argc, argv)
  475. int argc;
  476. char *argv[];
  477. {
  478.     char buf [512];
  479.     char *cp = buf;
  480.     while (argc-- > 1) {
  481.         char *cq = *++argv;
  482.         while (*cp++ = *cq++);
  483.         cp[-1] = ' ';
  484.     }
  485.     cp[-1] = '\n';
  486.     cp[0] = '\0';
  487.     openlog ("sendlog");
  488.     syslog (LOG_INFO, buf);
  489.     closelog ();
  490. }
  491.  
  492. SHAR_EOF
  493. if test 370 -ne "`wc -c < 'sendlog.c'`"
  494. then
  495.     echo shar: "error transmitting 'sendlog.c'" '(should have been 370 characters)'
  496. fi
  497. fi
  498. exit 0
  499. #    End of shell archive
  500.